%%%---------------------------------------------------------------------------------------
%%% @author    Stuart Jackson <sjackson@simpleenigma.com> [http://erlsoft.org]
%%% @copyright 2006 - 2007 Simple Enigma, Inc. All Rights Reserved.
%%% @doc       ERML core commands
%%% @reference See <a href="http://erlsoft.org/modules/erlweb" target="_top">Erlang Software Framework</a> for more information
%%% @reference See <a href="http://erlweb.googlecode.com" target="_top">ErlWeb Google Code Repository</a> for more information
%%% @version   0.0.2
%%% @since     0.0.2
%%% @end
%%%
%%%
%%% The MIT License
%%%
%%% Copyright (c) 2007 Stuart Jackson, Simple Enigma, Inc. All Righs Reserved
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
%%% in the Software without restriction, including without limitation the rights
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%%% copies of the Software, and to permit persons to whom the Software is
%%% furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in
%%% all copies or substantial portions of the Software.
%%%
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%%% THE SOFTWARE.
%%%
%%%
%%%---------------------------------------------------------------------------------------
-module(erml_core).
-author('sjackson@simpleenigma.com').
-vsn("0.0.2").
-include("../include/erml.hrl").
-include_lib("xmerl/include/xmerl.hrl").

-behavior(gen_erml).

-export([ermlcommand/2,ermlcookie/2,ermlfile/2,ermlinclude/2,ermlif/2,ermloutput/2,ermlset/2,ermlloop/2,ermlelse/2,ermlelseif/2]).

ermlcommand(Element,ERML) -> {Element,ERML}.

ermlelse(Element,ERML)    -> ermlcommand(Element,ERML).
ermlelseif(Element,ERML)  -> ermlcommand(Element,ERML).
ermloutput(Element,ERML)  -> ermlcommand(Element,ERML).





%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ermlcookie(Element,ERML) ->
	Attrib = lists:nth(1,Element#xmlElement.attributes),
	Key = Attrib#xmlAttribute.name,
	Value = Attrib#xmlAttribute.value,
	Eval = erml_eval:eval(Value,ERML),
	io:format("~p ~p ~p~n",[Key,Value,Eval]),
	case Eval of
		false ->
			case Value of
				"false" -> V = false;
				_ -> V = Value
			end;
		_ -> V = Eval
	end,
	NewERML = ERML#erml{response=[{"set-cookie",V}|ERML#erml.response]},
	{#xmlElement{name=ermlcommand},NewERML}.




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


ermlfile(Element,ERML) ->
	Action = list_to_atom(gen_erml:get_xml_attribute_value(Element,action)),
	io:format("~p~n",[Action]),
	case Action of
		append  -> ermlfile_write(Element,ERML,[append]);
		copy    -> ermlfile_copy(Element,ERML);
		move    -> ermlfile_move(Element,ERML);
		rename  -> ermlfile_move(Element,ERML);
		delete  -> ermlfile_delete(Element,ERML);
		exists  -> ermlfile_exists(Element,ERML);
		read    -> ermlfile_read(Element,ERML);
		write   -> ermlfile_write(Element,ERML);
		_       -> {#xmlElement{name=ermlcommand},ERML}
	end.


ermlfile_delete(Element,ERML) -> 
	FileName = gen_erml:get_xml_attribute_value(Element,filename),
	BaseDir = filename:dirname(ERML#erml.filename),
	FilePath = filename:join([BaseDir,FileName]),
	case filelib:is_regular(FilePath) of
		true -> file:delete(FilePath);
		_ -> ok
	end,
	{#xmlElement{name=ermlcommand},ERML}.

ermlfile_copy(Element,ERML) -> 
	Source = gen_erml:get_xml_attribute_value(Element,source),
	Dest = gen_erml:get_xml_attribute_value(Element,destination),
	BaseDir = filename:dirname(ERML#erml.filename),
	SourcePath = filename:join([BaseDir,Source]),
	DestPath = filename:join([BaseDir,Dest]),
	case filelib:is_regular(SourcePath) of
		true -> 
			case filelib:is_regular(DestPath) of
				true -> file:delete(DestPath);
				_ -> ok
			end,
			file:copy(SourcePath,DestPath);
		_ -> ok
	end,
	{#xmlElement{name=ermlcommand},ERML}.

ermlfile_move(Element,ERML) -> 
	Source = gen_erml:get_xml_attribute_value(Element,source),
	Dest = gen_erml:get_xml_attribute_value(Element,destination),
	BaseDir = filename:dirname(ERML#erml.filename),
	SourcePath = filename:join([BaseDir,Source]),
	DestPath = filename:join([BaseDir,Dest]),
	case filelib:is_regular(SourcePath) of
		true -> 
			case filelib:is_regular(DestPath) of
				true -> file:delete(DestPath);
				_ -> ok
			end,
			file:copy(SourcePath,DestPath);
		_ -> ok
	end,
	file:delete(SourcePath),
	{#xmlElement{name=ermlcommand},ERML}.

ermlfile_exists(Element,ERML) -> 
	Var = list_to_atom(gen_erml:get_xml_attribute_value(Element,variable)),
	FileName = gen_erml:get_xml_attribute_value(Element,filename),
	BaseDir = filename:dirname(ERML#erml.filename),
	FilePath = filename:join([BaseDir,FileName]),
	case filelib:is_regular(FilePath) of
		true -> Status = "true" ;
		_ -> Status = "false"
	end,
	io:format("~p~n",[Status]),
	NewERML = erml_cmd:internal_set(ERML,Var,Status),
	{#xmlElement{name=ermlcommand},NewERML}.





ermlfile_read(Element,ERML) -> 
	Var = list_to_atom(gen_erml:get_xml_attribute_value(Element,variable)),
	FileName = gen_erml:get_xml_attribute_value(Element,filename),
	BaseDir = filename:dirname(ERML#erml.filename),
	FilePath = filename:join([BaseDir,FileName]),
	case file:read_file(FilePath) of
		{ok, Bin} when is_binary(Bin) -> File = binary_to_list(Bin);
		_ -> File = "Error reading file"
	end,
	NewERML = erml_cmd:internal_set(ERML,Var,File),
	{#xmlElement{name=ermlcommand},NewERML}.



ermlfile_write(Element,ERML) -> ermlfile_write(Element,ERML,[]).
ermlfile_write(Element,ERML,Modes) -> 
	File = gen_erml:get_xml_attribute_value(Element,file),
	Eval = erml_cmd:if_var_sub(File,ERML),
	FileName = gen_erml:get_xml_attribute_value(Element,filename),
	BaseDir = filename:dirname(ERML#erml.filename),
	FilePath = filename:join([BaseDir,FileName]),
	case Eval of
		Atom when is_atom(Atom) -> file:write_file(FilePath,list_to_binary(atom_to_list(Atom)),Modes);
		List when is_list(List) -> file:write_file(FilePath,list_to_binary(List),Modes);
		Bin when is_binary(Bin) -> file:write_file(FilePath,Bin,Modes)
	end,
	{#xmlElement{name=ermlcommand},ERML}.




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ermlif(Element,ERML) -> 
%	io:format("~p~n",[Element#xmlElement.content]),
	Condition = gen_erml:get_xml_attribute_value(Element,condition),
	ERMLIF = build_if(Element#xmlElement.content,Condition),
%	io:format("~p~n",[ERMLIF]),
	process_if(ERMLIF#ermlif.conditions,ERMLIF#ermlif.else,ERML).


process_if([H|T],Else,ERML) ->
	{Condition,Elements} = H,
	Eval = erml_eval:eval(Condition,ERML),
	case Eval of
		false -> process_if(T,Else,ERML); %{#xmlElement{name=ermlcommand},ERML};
		0 -> process_if(T,Else,ERML); %{#xmlElement{name=ermlcommand},ERML};
		0.0 -> process_if(T,Else,ERML); %{#xmlElement{name=ermlcommand},ERML};
		true -> {#xmlElement{name=ermlcommand,content=Elements},ERML};
		Integer when is_integer(Integer),Integer > 0 ->
			{#xmlElement{name=ermlcommand,content=Elements},ERML};
		Float when is_float(Float),Float > 0 ->
			{#xmlElement{name=ermlcommand,content=Elements},ERML};
		_AnythingElse -> process_if(T,Else,ERML) %{#xmlElement{name=ermlcommand},ERML}
	end;
process_if([],Else,ERML) -> 
	{false,Elements} = Else,
	{#xmlElement{name=ermlcommand,content=Elements},ERML}.
	




build_if(Element,Condition) -> build_if(Element,Condition,#ermlif{},[]).

build_if([H|T],Condition,ERMLIF,Elements) when is_record(H,xmlText) -> 
	build_if(T,Condition,ERMLIF,[H|Elements]);
build_if([H|T],Condition,ERMLIF,Elements) when is_record(H,xmlElement) -> 
	case H#xmlElement.name of
		ermlelseif -> 
			NewCondition = gen_erml:get_xml_attribute_value(H,condition),
			build_if(T,NewCondition,ERMLIF#ermlif{conditions=[{Condition,lists:reverse(Elements)}|ERMLIF#ermlif.conditions]},[]);
		ermlelse -> 
			build_if(T,false,ERMLIF#ermlif{conditions=[{Condition,lists:reverse(Elements)}|ERMLIF#ermlif.conditions]},[]);
		_ -> build_if(T,Condition,ERMLIF,[H|Elements])
	end;
build_if([],Condition,ERMLIF,Elements) -> 
	case Condition of
		false -> ERMLIF#ermlif{conditions=lists:reverse(ERMLIF#ermlif.conditions),else={Condition,lists:reverse(Elements)}};
		_ -> 
			NewConditions = [{Condition,lists:reverse(Elements)}|ERMLIF#ermlif.conditions],
			ERMLIF#ermlif{conditions=lists:reverse(NewConditions),else={false,[]}}
	end.
	







%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ermlinclude(Element,ERML) ->
	Src = gen_erml:get_xml_attribute_value(Element,src),
	BaseDir = filename:dirname(ERML#erml.filename),
	FileName = filename:join([BaseDir,Src]),
%	io:format("~p~n",[FileName]),
	case filelib:is_regular(FileName) of
		true  -> 
			String = erml_cmd:read_erml(FileName),
			{XMLDoc,_Misc} = xmerl_scan:string("<ermloutput>" ++ String ++ "</ermloutput>"),
			{NewElement,_FinalERML} = erml:process(XMLDoc,ERML),
			{NewElement,ERML};
		false -> {#xmlElement{name=ermlcommand},ERML}
	end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


ermlloop(Element,ERML) ->
	Loop = build_loop(Element,ERML),
%	io:format("~p~n",[Loop]),
	case Loop of
		{ermlloop,Index,From,To,Step,[],[]} -> 
			Content = do_index_loop(Element,ERML,[],Index,From,To,Step),
			{#xmlElement{name=ermlcommand,content=Content},ERML};
		{ermlloop,_Index,[],[],_,_List,[]} -> 
			io:format("List Loop~n"),
			{#xmlElement{name=ermlcommand},ERML};
		{ermlloop,[],[],[],_,[],{condition,Condition,Status}} -> 
			case Status of
				false -> {#xmlElement{name=ermlcommand},ERML};
				true -> 
					Content = do_conditional_loop(Element,ERML,Condition,Status,[]),
					{#xmlElement{name=ermlcommand,content=Content},ERML}
			end;
		_ -> {#xmlElement{name=ermlcommand},ERML}
	end.

do_index_loop(_Element,_ERML,Acc,_Index,From,To,_Step) when From > To -> lists:reverse(Acc);
do_index_loop(Element,ERML,Acc,Index,From,To,Step) ->
	NewERML = erml_cmd:internal_set(ERML,Index,From),
	{NewElement,NextERML} = erml:process(Element#xmlElement.content,NewERML),
	do_index_loop(Element,NextERML,[NewElement|Acc],Index,From+Step,To,Step).

do_conditional_loop(_Element, _ERML, _Condition, false, Acc) -> lists:reverse(Acc);
do_conditional_loop(Element, ERML, Condition, true, Acc) ->
	{NewElement,NextERML} = erml:process(Element#xmlElement.content,ERML),
	NewStatus = erml_eval:eval(Condition,NextERML),
	do_conditional_loop(Element, NextERML, Condition, NewStatus, [NewElement|Acc]).

build_loop(Element,ERML) ->
	Index = loop_key(index,Element#xmlElement.attributes,ERML),
	From  = loop_key(from,Element#xmlElement.attributes,ERML),
	To    = loop_key(to,Element#xmlElement.attributes,ERML),
	List  = loop_key(list,Element#xmlElement.attributes,ERML),
	Cond  = loop_key(condition,Element#xmlElement.attributes,ERML),
	case loop_key(step,Element#xmlElement.attributes,ERML) of
		[] -> Step = 1;
		Step -> ok
	end,
	#ermlloop{index=Index,from=From,to=To,step=Step,list=List,condition=Cond}.

loop_key(Key,Attrib,ERML) ->
	case lists:keysearch(Key,2,Attrib) of
		{value,A} ->
			case Key of
				index     -> A#xmlAttribute.value;
				to        -> erml_eval:eval(A#xmlAttribute.value,ERML);
				from      -> erml_eval:eval(A#xmlAttribute.value,ERML);
				step      -> erml_eval:eval(A#xmlAttribute.value,ERML);
				list      -> A#xmlAttribute.value;
				condition -> {condition,A#xmlAttribute.value,erml_eval:eval(A#xmlAttribute.value,ERML)}
			end;
		_ -> []
	end.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


ermlset(Element,ERML) ->
%	io:format("~p~n",[ERML#erml.var]),
	Attrib = lists:nth(1,Element#xmlElement.attributes),
	Key = Attrib#xmlAttribute.name,
	Value = Attrib#xmlAttribute.value,
	Eval = erml_eval:eval(Value,ERML),
%	io:format("~p ~p ~p~n",[Key,Value,Eval]),
	case Eval of
		false ->
			case Value of
				"false" -> V = false;
				_ -> V = Value
			end;
		_ -> V = Eval
	end,
	{#xmlElement{name=ermlcommand},erml_cmd:internal_set(ERML,Key,V)}.